﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using ResourceLoadBalancer.WebServices.Contracts.Data;
using ResourceLoadBalancer.DataAccess;
using System.Configuration;
using System.Threading;
using System.Data.SqlClient;
using Microsoft.Samples.SqlServer;
using System.IO;
using System.Xml;
using System.Data;

namespace ResourceLoadBalancer.WebServices
{
    // NOTE: If you change the class name "ResourceLoadBalancerService" here, you must also update the reference to "ResourceLoadBalancerService" in App.config.
    public class ResourceLoadBalancerService : IResourceLoadBalancerService
    {
        public IList<ResourceURIDataContract> GetResourceURIs(string uri)
        {
            string connectionString = ConfigurationManager.ConnectionStrings["ResourceLoadBalancerDatabase"].ConnectionString;

            ResourceLoadBalancerDataContext ctx = new ResourceLoadBalancerDataContext(connectionString);

            string hash = (from resourceURI in ctx.ResourceURIs
                           where resourceURI.URI == uri
                           select resourceURI.ResourceHash).First();

            IList<ResourceURIDataContract> locations = (from resourceURI in ctx.ResourceURIs
                                                  join resource in ctx.Resources on resourceURI.ResourceHash equals resource.Hash
                                                  where resourceURI.ResourceHash == hash
                                                  select new ResourceURIDataContract(resourceURI)).ToList();

            return locations;
        }

        public void AddResource(ResourceDataContract resource)
        {
            string connectionString = ConfigurationManager.ConnectionStrings["ResourceLoadBalancerDatabase"].ConnectionString;

            ResourceLoadBalancerDataContext ctx = new ResourceLoadBalancerDataContext(connectionString);

            if (resource != null)
            {
                int exists = (from r in ctx.Resources
                              where r.Hash == resource.Hash
                              select r.Hash).Count();

                if (exists == 0)
                {
                    ctx.Resources.InsertOnSubmit(resource.ConvertDataContractToEntity());
                    try
                    {
                        ctx.SubmitChanges();
                    }
                    catch (Exception)
                    {
                    }

                }
            }
        }

        public void AddResources(IList<ResourceDataContract> resources)
        {
            Parallel.ForEach(resources, resource =>
	        {
                AddResource(resource);
            });
        }

        

        public ResourceURIDataContract AddResourceURI(ResourceURIDataContract resourceURI)
        {
            string connectionString = ConfigurationManager.ConnectionStrings["ResourceLoadBalancerDatabase"].ConnectionString;

            ResourceLoadBalancerDataContext ctx = new ResourceLoadBalancerDataContext(connectionString);

            if (resourceURI != null)
            {
                ResourceURI newResourceURI = resourceURI.ConvertDataContractToEntity();


                int exists = (from ru in ctx.ResourceURIs
                              where ru.ResourceHash == resourceURI.ResourceHash &&
                                    ru.URIHash == resourceURI.URIHash
                              select ru.Id).Count();

                if (exists == 0)
                {
                    ctx.ResourceURIs.InsertOnSubmit(newResourceURI);
                    try
                    {
                        ctx.SubmitChanges();
                    }
                    catch (Exception)
                    {
                    }
                }

                resourceURI.ConvertEntityToDataContract(newResourceURI);
            }
            return resourceURI;
        }

        public void AddResourceURIs(IList<ResourceURIDataContract> resourceURIs)
        {
            Parallel.ForEach(resourceURIs, resourceURI =>
            {
                AddResourceURI(resourceURI);
            });
        }

        public ResourceURIDataContract GetResourceURI(ResourceURIDataContract resourceURI)
        {
            string connectionString = ConfigurationManager.ConnectionStrings["ResourceLoadBalancerDatabase"].ConnectionString;

            ResourceLoadBalancerDataContext ctx = new ResourceLoadBalancerDataContext(connectionString);

            try
            {
                ResourceURIDataContract selectedResourceURI = (from ru in ctx.ResourceURIs
                                                               where ru.URI == resourceURI.URI &&
                                                                    ru.HostName == resourceURI.HostName
                                                               select new ResourceURIDataContract(ru.Id,
                                                                   ru.URI,
                                                                   ru.ResourceHash,
                                                                   ru.HostName,
                                                                   ru.URIHash,
                                                                   ru.Owner,
                                                                   ru.LastModifiedDate,
                                                                   ru.CreatedDate,
                                                                   ru.InventoryDate)
                                                               ).DefaultIfEmpty().First();
                return selectedResourceURI;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public void CleanResourceURIs(string hostName, string path)
        {
            string connectionString = ConfigurationManager.ConnectionStrings["ResourceLoadBalancerDatabase"].ConnectionString;
            SqlConnection connection = new SqlConnection(connectionString);
            SqlCommand cleanResourceURIsCommand = new SqlCommand("DELETE FROM ResourcesURIs WHERE uri LIKE '" + path + "%' AND hostName = @hostName", connection);
            SqlParameter hostNameParameter = new SqlParameter("@hostName",SqlDbType.VarChar);
            hostNameParameter.Value = hostName;
            cleanResourceURIsCommand.Parameters.Add(hostNameParameter);
            
            cleanResourceURIsCommand.CommandTimeout = 0;
            if (path != null)
            {
                try
                {
                    connection.Open();
                    cleanResourceURIsCommand.ExecuteNonQuery();

                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }
                finally
                {
                    connection.Close();
                }
            }

 
        }
        
        public void ConfigureQueuing(string hostName, string queueType, string queueName)
        {
            string connectionString = ConfigurationManager.ConnectionStrings["ResourceLoadBalancerDatabase"].ConnectionString;
            SqlConnection connection = new SqlConnection(connectionString);

            if (hostName != null &&
                queueType != null &&
                queueName != null)
            {
                SqlCommand createSendQueueCommand = new SqlCommand("CREATE QUEUE [" + queueType + "SendQueue_" + hostName + "_" + queueName + "]", connection);
                SqlCommand createReceiveQueueCommand = new SqlCommand("CREATE QUEUE [" + queueType + "ReceiveQueue_" + hostName + "_" + queueName + "]", connection);
                SqlCommand createSendServiceCommand = new SqlCommand("CREATE SERVICE [" + queueType + "SendURIService_" + hostName + "_" + queueName + "] ON QUEUE [FileSystemSendQueue_" + hostName + "_" + queueName + "] (ScannedResourceURIContract)", connection);
                SqlCommand createReceiveServiceCommand = new SqlCommand("CREATE SERVICE [" + queueType + "ReceiveURIService_" + hostName + "_" + queueName + "] ON QUEUE [FileSystemReceiveQueue_" + hostName + "_" + queueName + "] (ScannedResourceURIContract)", connection);

                try
                {
                    connection.Open();

                    try
                    {
                        createSendQueueCommand.ExecuteNonQuery();
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.Message);
                    }

                    try
                    {
                        createReceiveQueueCommand.ExecuteNonQuery();
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.Message);
                    }

                    try
                    {
                        createSendServiceCommand.ExecuteNonQuery();
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.Message);
                    }
                    try
                    {
                        createReceiveServiceCommand.ExecuteNonQuery();
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.Message);
                    }

                    
                }
                catch (Exception ex)
                {
                    throw ex;
                }
                finally
                {
                    connection.Close();
                }
            }
        }

        public void DeconfigureQueuing(string hostName, string queueType, string queueName)
        {
            string connectionString = ConfigurationManager.ConnectionStrings["ResourceLoadBalancerDatabase"].ConnectionString;
            SqlConnection connection = new SqlConnection(connectionString);

            if (hostName != null &&
                queueType != null &&
                queueName != null)
            {
                SqlCommand dropSendServiceCommand = new SqlCommand("DROP SERVICE [" + queueType + "SendURIService_" + hostName + "_" + queueName + "]", connection);
                dropSendServiceCommand.CommandTimeout = 0;
                
                SqlCommand dropReceiveServiceCommand = new SqlCommand("DROP SERVICE [" + queueType + "ReceiveURIService_" + hostName + "_" + queueName + "]", connection);
                dropReceiveServiceCommand.CommandTimeout = 0;

                SqlCommand dropSendQueueCommand = new SqlCommand("DROP QUEUE [" + queueType + "SendQueue_" + hostName + "_" + queueName + "]", connection);
                dropSendQueueCommand.CommandTimeout = 0;

                SqlCommand dropReceiveQueueCommand = new SqlCommand("DROP QUEUE [" + queueType + "ReceiveQueue_" + hostName + "_" + queueName + "]", connection);
                dropReceiveQueueCommand.CommandTimeout = 0;

                try
                {
                    connection.Open();
                    try
                    {
                        dropSendServiceCommand.ExecuteNonQuery();
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.Message);
                    }
                    try
                    {
                        dropReceiveServiceCommand.ExecuteNonQuery();
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.Message);
                    }

                    try
                    {
                        dropSendQueueCommand.ExecuteNonQuery();
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.Message);
                    }

                    try
                    {
                        dropReceiveQueueCommand.ExecuteNonQuery();
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.Message);
                    }    

                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }
                finally
                {
                    connection.Close();
                }
            }
        }



        public void QueueFileSystemResourceURI(ResourceURIDataContract resourceURI, ref SqlConnection connection,ref string hostName,ref string queueName)
        {
            if (connection == null)
            {
                string connectionString = ConfigurationManager.ConnectionStrings["ResourceLoadBalancerDatabase"].ConnectionString;

                connection = new SqlConnection(connectionString);

                connection.Open();
            }

            SqlTransaction transaction = connection.BeginTransaction();
            Service sendScannedFileSystemResourceURIService = new Service("FileSystemSendURIService_"+ hostName + "_" + queueName, connection, transaction);

            Conversation conversation = sendScannedFileSystemResourceURIService.BeginDialog("FileSystemReceiveURIService_" + hostName + "_" + queueName, null, "ScannedResourceURIContract", TimeSpan.FromDays(5), false, connection, transaction);

            Message message = new Message("ScannedResourceURI", null);

            string queueItem = "<ResourceURI>" + resourceURI.URI + "</ResourceURI>";
            byte[] bytes = System.Text.Encoding.ASCII.GetBytes(queueItem);
            MemoryStream stream = new MemoryStream(bytes);

            message.Body = stream;

            conversation.Send(message, connection, transaction);
            conversation.End(connection, transaction);
            transaction.Commit();
            //connection.Close();
        }

        public void QueueFileSystemResourceURIs(string hostName, string queueName, IList<ResourceURIDataContract> resourceURIs)
        {
            string connectionString = ConfigurationManager.ConnectionStrings["ResourceLoadBalancerDatabase"].ConnectionString;

            SqlConnection connection = new SqlConnection(connectionString);

            connection.Open();

            foreach(ResourceURIDataContract resourceURI in resourceURIs)
            {
                QueueFileSystemResourceURI(resourceURI,ref connection,ref hostName, ref queueName);
            };

            connection.Close();
        }

        public string GetQueuedFileSystemResourceURI(string hostName, string queueName)
        {
            string connectionString = ConfigurationManager.ConnectionStrings["ResourceLoadBalancerDatabase"].ConnectionString;
            string queueItem = "";

            SqlConnection connection = new SqlConnection(connectionString);

            connection.Open();
            SqlTransaction transaction = connection.BeginTransaction();
            Service receiveScannedFileSystemResourceURIService = null;
            Conversation conversation = null;
            Message message = null;

            try
            {
                receiveScannedFileSystemResourceURIService = new Service("FileSystemReceiveURIService_" + hostName + "_" + queueName, connection, transaction);
                receiveScannedFileSystemResourceURIService.FetchSize = 1;
                
                conversation = receiveScannedFileSystemResourceURIService.GetConversation(connection, transaction);    
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
            if (conversation != null)
            {
                message = conversation.Receive();

                if (message != null)
                {
                    if (message.Body != null)
                    {
                        TextReader reader = new StreamReader(message.Body);
                        queueItem = reader.ReadToEnd();
                    }
                }
                conversation.End(connection, transaction);
                transaction.Commit();
                connection.Close();
            }

            return queueItem;
        }

        public void QueueSharePointResourceURI(SharePointURIDataContract resourceURI)
        {
            string connectionString = ConfigurationManager.ConnectionStrings["ResourceLoadBalancerDatabase"].ConnectionString;

            SqlConnection connection = new SqlConnection(connectionString);

            connection.Open();
            SqlTransaction transaction = connection.BeginTransaction();
            Service sendScannedFileSystemResourceURIService = new Service("SendScannedSharePointResourceURIService", connection, transaction);

            Conversation conversation = sendScannedFileSystemResourceURIService.BeginDialog("ReceiveScannedSharePointResourceURIService", null, "ScannedResourceURIContract", TimeSpan.FromDays(1), false, connection, transaction);

            Message message = new Message("ScannedResourceURI", null);


            string queueItem = resourceURI.ConvertToXmlDocument().OuterXml;
            byte[] bytes = System.Text.Encoding.ASCII.GetBytes(queueItem);
            
            MemoryStream stream = new MemoryStream(bytes);

            message.Body = stream;

            conversation.Send(message, connection, transaction);
            conversation.End(connection, transaction);
            transaction.Commit();
            connection.Close();
        }

        public SharePointURIDataContract GetQueuedSharePointResourceURI()
        {
            string connectionString = ConfigurationManager.ConnectionStrings["ResourceLoadBalancerDatabase"].ConnectionString;

            SqlConnection connection = new SqlConnection(connectionString);

            connection.Open();
            SqlTransaction transaction = connection.BeginTransaction();
            Service receiveScannedFileSystemResourceURIService = new Service("ReceiveScannedSharePointResourceURIService", connection, transaction);
            receiveScannedFileSystemResourceURIService.FetchSize = 1;
            
            Conversation conversation = receiveScannedFileSystemResourceURIService.GetConversation(connection, transaction);
            Message message = null;
            if (conversation != null)
            {
                message = conversation.Receive();
            }

            SharePointURIDataContract queueItem = new SharePointURIDataContract();

            if (message != null)
            {
                if (message.Body != null)
                {
                    TextReader reader = new StreamReader(message.Body);
                    XmlDocument document = new XmlDocument();
                    //string readerOutput = reader.ReadToEnd();
                    document.Load(reader);
                    queueItem.ConvertFromXmlDocument(document);
                }
            }

            conversation.End(connection,transaction);

            transaction.Commit();
            connection.Close();

            return queueItem;
        }

        public bool IsServiceAvailable()
        {
            return true;
        }
    }
}
